package chapt06.smoother;
// Triangle.java
// OpenGL SuperBible
// Demonstrates OpenGL Triangle Fans, backface culling, and depth testing
// Program by Richard S. Wright Jr.

import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GL2;
import javax.media.opengl.glu.GLU;

import java.util.Random;

public class Smoother
{
	static GLAutoDrawable glautodrawable;
	static GLU glu = new GLU();
	
	// Array of small stars
	static int SMALL_STARS = 100;
	static float vSmallStars[][] = new float[SMALL_STARS][2];
	
	static int MEDIUM_STARS = 40;
	static float vMediumStars[][] = new float[MEDIUM_STARS][2];
	
	static int LARGE_STARS = 15;
	static float vLargeStars[][] = new float[LARGE_STARS][2];
	
	static int SCREEN_X = 800;
	static int SCREEN_Y = 600;
	
	static int processMenuValue = 2;
		
	///////////////////////////////////////////////////////////////////////////////
	// Reset flags as appropriate in response to menu selections
	public static void processMenu(GL2 gl2, int value)
	{
		switch(value)
		{
			case 1:
				// Turn on antialiasing, and give hint to do the best
	            // job possible.
				gl2.glBlendFunc(GL2.GL_SRC_ALPHA, GL2.GL_ONE_MINUS_SRC_ALPHA);
				gl2.glEnable(GL2.GL_BLEND);
				gl2.glEnable(GL2.GL_POINT_SMOOTH);
				gl2.glHint(GL2.GL_POINT_SMOOTH_HINT, GL2.GL_NICEST);
				gl2.glEnable(GL2.GL_LINE_SMOOTH);
				gl2.glHint(GL2.GL_LINE_SMOOTH_HINT, GL2.GL_NICEST);
				gl2.glEnable(GL2.GL_POLYGON_SMOOTH);
				gl2.glHint(GL2.GL_POLYGON_SMOOTH_HINT, GL2.GL_NICEST);
				break;
				
			case 2:
				// Turn off blending and all smoothing
				gl2.glDisable(GL2.GL_BLEND);
				gl2.glDisable(GL2.GL_LINE_SMOOTH);
				gl2.glDisable(GL2.GL_POINT_SMOOTH);
				gl2.glDisable(GL2.GL_POLYGON_SMOOTH);
				break;

			default:
				break;
		}		
	}
	
	// Setup the rendering state
	protected static void setupRC(GL2 gl2, int w, int h)
	{
		int i;
		Random random = new Random();
		
		// Populate star list
		for(i = 0; i < SMALL_STARS; i++)
		{
			vSmallStars[i][0] = (float)random.nextInt(SCREEN_X);
			vSmallStars[i][1] = (float)random.nextInt(SCREEN_Y - 100) + 100.0f;
		}
		
		// Populate star list
		for(i = 0; i < MEDIUM_STARS; i++)
		{
			vMediumStars[i][0] = (float)random.nextInt(SCREEN_X * 10) / 10.0f;
			vMediumStars[i][1] = (float)random.nextInt(SCREEN_Y - 100) + 100.0f;
		}
		
		// Populate the star list
		for(i = 0; i < LARGE_STARS; i++)
		{
			vLargeStars[i][0] = (float)random.nextInt(SCREEN_X * 10) / 10.0f;
			vLargeStars[i][1] = (float)random.nextInt(SCREEN_Y - 100) + 100.0f;
		}
		
		// Black background
		gl2.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
		
		// Set drawing color to white
		gl2.glColor3f(0.0f, 0.0f, 0.0f);
	}
	
	///////////////////////////////////////////////////
	// Called to draw scene
	protected static void renderScene(GL2 gl2, int w, int h)
	{
		processMenu(gl2, processMenuValue);
		
		int i;              // Loop variable
		float x = 700.0f;   // Location and radius of moon
		float y = 500.0f;
		float r = 50.0f;
		float angle = 0.0f; // Another looping variable
		
		// Clear the window
		gl2.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);
		
		// Everything is white
		gl2.glColor3f(1.0f, 1.0f, 1.0f);
		
		// Draw small stars
		gl2.glPointSize(1.0f);
		gl2.glBegin(GL2.GL_POINTS);
			for(i = 0; i < SMALL_STARS; i++)
				gl2.glVertex2fv(vSmallStars[i], 0);
		gl2.glEnd();
		
		// Draw medium sized stars
		gl2.glPointSize(3.05f);
		gl2.glBegin(GL2.GL_POINTS);
			for(i = 0; i < MEDIUM_STARS; i++)
				gl2.glVertex2fv(vMediumStars[i], 0);
		gl2.glEnd();
		
		// Draw largest stars
		gl2.glPointSize(5.5f);
		gl2.glBegin(GL2.GL_POINTS);
			for(i = 0; i < LARGE_STARS; i++)
				gl2.glVertex2fv(vLargeStars[i], 0);
		gl2.glEnd();
		
		// Draw the "moon"
		gl2.glBegin(GL2.GL_TRIANGLE_FAN);
			gl2.glVertex2f(x, y);
			for(angle = 0; angle < 2.0f * 3.141592f; angle += 0.1f)
				gl2.glVertex2f(x + (float)Math.cos(angle) * r, y + (float)Math.sin(angle) * r);
				gl2.glVertex2f(x + r, y);
		gl2.glEnd();
		
		// Draw distant horizon
		gl2.glLineWidth(3.5f);
		gl2.glBegin(GL2.GL_LINE_STRIP);
			gl2.glVertex2f(0.0f, 25.0f);
			gl2.glVertex2f(50.0f, 100.0f);
			gl2.glVertex2f(100.0f, 25.0f);
			gl2.glVertex2f(225.0f, 125.0f);
			gl2.glVertex2f(300.0f, 50.0f);
			gl2.glVertex2f(375.0f, 100.0f);
			gl2.glVertex2f(460.0f, 25.0f);
			gl2.glVertex2f(525.0f, 100.0f);
			gl2.glVertex2f(600.0f, 20.0f);
			gl2.glVertex2f(675.0f, 70.0f);
			gl2.glVertex2f(750.0f, 25.0f);
			gl2.glVertex2f(800.0f, 90.0f);
		gl2.glEnd();
		
		// Swap buffers
		gl2.glFlush();
	}
	
	public static void changeSize(GL2 gl2, int w, int h)
	{
		// Prevent a divide by zero
		if(h == 0)
			h = 1;
		
		// Set Viewport to window dimensions
		gl2.glViewport(0, 0, w, h);
		
		// Reset projection matrix stack
		gl2.glMatrixMode(GL2.GL_PROJECTION);
		gl2.glLoadIdentity();
		
		// Establish clipping volume (left, right, bottom, top, near, far)
		glu.gluOrtho2D(0.0, SCREEN_X, 0.0, SCREEN_Y);
		
		// Reset Model view matrix stack
		gl2.glMatrixMode(GL2.GL_MODELVIEW);
		gl2.glLoadIdentity();		
	}
}